package model;

import java.awt.Color;
import java.awt.Point;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Observable;

import javax.swing.ImageIcon;

/**
 * This class represents a territory in the game. It contains a name, a list of
 * its neighbors, its containing continent, the Player who owns it, the number
 * of troops stationed in it, its color signature, and a map reference.
 * 
 * @author David Shefchik
 * 
 * 
 */
public class Territory extends Observable implements Serializable {

	private String name;
	private ArrayList<Territory> neighbors;
	private Continent motherland;
	private Player ruler;
	private int troopsStationed;
	private int colorSignature;
	private Point labelPoint;
	private Map map;

	/**
	 * 
	 * The constructor takes in a name, a continent and a map. It assigns
	 * 
	 * @param name
	 *            is the name of this Territory.
	 * @param continent
	 *            is the continent this Terrtory locate.
	 * @param map
	 *            is the map in which this Territory is used, new Terriroty are
	 *            created in map class.
	 */
	public Territory(String name, Continent continent, Map map) {
		this.name = name;
		this.neighbors = new ArrayList<Territory>();
		this.map = map;
		motherland = continent;
		ruler = new NullPlayer("noname", null, null);
		troopsStationed = 0;
		int x = 50;// (int) ((Math.random()*600)/1);
		int y = 50;// (int) ((Math.random()*600)/1);
		setPoint(new Point(x, y)); // default
		continent.addTerritory(this);
		this.addObserver(continent);

	}

	/**
	 * Returns a reference to the map this territory is in.
	 * 
	 * @return the map which has this Territory in.
	 */
	public Map getMap() {
		return this.map;
	}

	/**
	 * Returns the owner of this territory.
	 * 
	 * @return the player who has this Territory.
	 */
	public Player getRuler() {
		return this.ruler;

	}

	/**
	 * This method takes in a Player and sets the owner of this territory to be
	 * that player
	 * 
	 * @param newPlayer
	 *            is the given new ruler;
	 */
	public void setRuler(Player newPlayer) {
		this.ruler = newPlayer;
		this.hasChanged();
		this.notifyObservers(this);
	}

	/**
	 * Returns this territory's name
	 * 
	 * @return the name of this Territory.
	 */
	public String getTerritoryName() {
		return this.name;
	}

	/**
	 * Returns the number of troops currently stationed in this territory
	 * 
	 * @return the number of troops stay in this Territory.
	 */
	public int getTroopNumber() {
		return this.troopsStationed;
	}

	/**
	 * This method takes in an integer and adds that amount to the number of
	 * troops stationed in this territory. It first checks to see if the integer
	 * is positive.
	 * 
	 * @param Troopadded
	 *            should be a positive integer, this is the number to be added.
	 * @return true if successful added a positive troop. false otherwise.
	 */
	public boolean addTroop(int Troopadded) {
		if (Troopadded > 0) {
			this.troopsStationed += Troopadded;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * This method removes the given number troops from the territory. This
	 * method will first check whether the given number is positive, then it
	 * will check whether there are enough troops in this territory to remove
	 * that number.
	 * 
	 * @param TroopToRemove
	 *            is the given positive integer to remove from troop in
	 *            territory.
	 * @return false if TroopToRemove is not positive or the troop in Territory
	 *         is not enough. true otherwise.
	 */
	public boolean removeTroop(int TroopToRemove) {
		if (TroopToRemove <= 0) {
			return false;
		}

		if (this.troopsStationed >= TroopToRemove) {
			this.troopsStationed -= TroopToRemove;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * This method takes in a Territory and then checks to see if that Territory
	 * is in this Territory's list of neighbors.
	 * 
	 * @param otherTerritory
	 *            is the given Territory to check.
	 * @return true if it's a neighbor, false otherwise.
	 */
	public boolean hasNeighbor(Territory otherTerritory) {
		return this.neighbors.contains(otherTerritory);
	}

	/**
	 * This method adds a new Territory to this Territoy's list of neighbors.
	 * There are three conditions: 1. Both this and toAdd don't has each other
	 * as neighbor, then they both add neighbor. 2. one has the other as
	 * neighbor, then that one add neighbor. 3. They both have each other as
	 * neighbors, then nothing occurs.
	 * 
	 * @param toAdd
	 *            is another Territory to add as a neighbor.
	 */
	public void addNeighbor(Territory toAdd) {
		if (!hasNeighbor(toAdd) && !toAdd.hasNeighbor(this)) {
			this.neighbors.add(toAdd);
			this.hasChanged();
			this.notifyObservers(this);
			toAdd.addNeighbor(this);
		} else if (!hasNeighbor(toAdd) && toAdd.hasNeighbor(this)) {
			this.neighbors.add(toAdd);
			this.hasChanged();
			this.notifyObservers(this);
		} else if (hasNeighbor(toAdd) && !toAdd.hasNeighbor(this)) {
			toAdd.addNeighbor(this);
		} else {
		}
	}

	/**
	 * This method returns all the neighbors of this Territory in an ArrayList.
	 * NOTICE: This method is not to be used until all neighbor relationships
	 * are finalized.
	 * 
	 * @return a ArrayList which contains all neighbors of this Territory.
	 */
	public ArrayList<Territory> listNeighbors() {
		return this.neighbors;
	}

	/**
	 * Returns the continent in which this territory is contained.
	 * 
	 * @return the continent where this Territory is located.
	 */
	public Continent getContinent() {
		return this.motherland;
	}

	/**
	 * Sets the colorSignature for this Territory.
	 * 
	 * @param colorSignature
	 *            The signature of the color for this territory.
	 */
	public void setColorSignature(int colorSignature) {
		this.colorSignature = colorSignature;
	}

	/**
	 * Returns the color signature of this territory.
	 * 
	 * @return colorSignature The signature for the color of this territory.
	 */
	public int getColorSignature() {
		return colorSignature;
	}

	/**
	 * Returns the Territories name
	 * 
	 * @return String name
	 */
	public String toString() {
		return name;
	}

	/**
	 * Sets the point of the territory. Makes it possible to easily add a label
	 * to the territory representing ownership and troop strength.
	 * 
	 * @param labelPoint
	 */
	public void setPoint(Point labelPoint) {
		this.labelPoint = labelPoint;
	}

	/**
	 * Returns the point of the territory, representing its location in the map.
	 * 
	 * @return The territory's Point
	 */
	public Point getPoint() {
		return labelPoint;
	}

}
